package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.constants.Constants;
import com.tanhua.commons.constants.LogKey;
import com.tanhua.commons.constants.LogType;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VisitorsApi;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.enums.CommentSubject;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVO;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVO;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Xiao
 * @date 2021/10/25
 */
@Service
@Slf4j
public class MovementsService {
    @DubboReference
    private MovementApi movementApi;
    @Autowired
    private OssTemplate ossTemplate;
    @DubboReference
    private UserInfoApi userInfoApi;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @DubboReference
    private CommentApi commentApi;
    @DubboReference
    private VisitorsApi visitorsApi;

    @Autowired
    private UserFreezeService userFreezeService;
    @Autowired
    private MqMessageService mqMessageService;

    /**
     * 圈子-动态-发布
     * @param movement
     */
    public void movements(Movement movement, MultipartFile imageContent[]) throws IOException {
        //获取当前登录的用户id
        Long userId = UserHolder.getUserId();
        //检查用户冻结状态
        userFreezeService.checkUserStatus("3", userId);
        //判断发布的动态内容是否存在
        boolean empty = StringUtils.isEmpty(movement.getTextContent());
        if (empty) {
            throw new BusinessException(ErrorResult.contentError());
        }
        //将文件内容上传到阿里云OSS，获取请求地址
        List<String> medias = new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            String media = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
            medias.add(media);
        }
        //将数据封装到Movement对象
        movement.setUserId(userId);
        movement.setMedias(medias);
        //调用API完成动态发布
        String movementId = movementApi.publish(movement);
        //发送日志
        mqMessageService.sendLogMessage(
                userId, LogType.MOVEMENT_PUBLISH, LogKey.MOVEMENT, movementId);
        //发送动态审核消息
        mqMessageService.sendAudiMessage(movementId);
    }

    /**
     * 圈子-我的动态
     * @param page
     * @param pagesize
     * @param userId
     * @return
     */
    public PageResult all(Integer page, Integer pagesize, Long userId) {
        //分页查询动态信息
        PageResult pageResult = movementApi.selectByUserId(page, pagesize, userId);
        return getPageResult(pageResult);
    }

    /**
     * 圈子-好友动态
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult findFriendMovements(Integer page, Integer pagesize) {
        //调用API查询好友动态详情数据
        Long userId = UserHolder.getUserId();
        PageResult pageResult = movementApi.findFriendMovements(page, pagesize, userId);
        //getPageResult()获取PageResult对象(封装了MovementsVO集合)并返回
        return getPageResult(pageResult);
    }

    /**
     * 圈子-推荐动态
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult recommend(Integer page, Integer pagesize) {
        //从redis获取推荐动态的pid
        Long userId = UserHolder.getUserId();
        String redisKey = Constants.MOVEMENTS_RECOMMEND + userId;
        String data = redisTemplate.opsForValue().get(redisKey);
        //判断推荐动态是否存在
        PageResult pageResult = new PageResult();
        List<Movement> movements = Collections.emptyList();
        if (StringUtils.isEmpty(data)) {
            //推荐动态为空，调用API随机构造10条推荐动态
            movements = movementApi.getRandomMovements(pagesize);
        } else {
            //推荐动态不为空，处理pid数据
            //截取data获取pid字符串数组
            String[] dataArr = data.split(",");
            //判断当前查询的页码是否有数据
            Integer counts = dataArr.length;
            Integer redisPage = counts % pagesize == 0 ? counts / pagesize : counts / pagesize + 1;
            //没有数据，直接返回PageResult对象(items为[])
            if (page > redisPage) {
                return pageResult;
            }
            //有数据，调用API根据pid数组查询推荐动态数据
            List<Long> pids = Arrays.stream(dataArr)
                    .skip((page - 1) * pagesize)    //分页skip
                    .limit(pagesize)    //分页limit
                    .map(Convert::toLong)   //类型转换
                    .collect(Collectors.toList());  //转List集合
            movements = movementApi.findRecommendMovements(pids);
        }
        //构造PageResult对象(封装了MovementsVO集合)并返回
        pageResult.setPage(page);
        pageResult.setPagesize(pagesize);
        pageResult.setItems(movements);
        return getPageResult(pageResult);
    }

    /**
     * 获取PageResult对象(封装了MovementsVO集合)
     * @param pageResult
     * @return
     */
    private PageResult getPageResult(PageResult pageResult) {
        List<Movement> movements = (List<Movement>) pageResult.getItems();
        //调用API查询动态发布人详情
        if (CollUtil.isEmpty(movements)) {
            return pageResult;
        }
        List<Long> userIds = CollUtil.getFieldValues(movements, "userId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.selectByIdsAndCondition(userIds, null);
        List<MovementsVO> movementsVOs = new ArrayList<>();
        //构造VO对象
        String hashLikeKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
        String hashLoveKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
        for (Movement movement : movements) {
            UserInfo userInfo = map.get(movement.getUserId());
            if (ObjectUtil.isNotEmpty(userInfo)) {
                MovementsVO movementsVO = MovementsVO.init(userInfo, movement);
                //获取redis中的hash数据，判断hasKey是否存在
                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toString();
                if (redisTemplate.opsForHash().hasKey(key, hashLikeKey)) {
                    movementsVO.setHasLiked(1);
                }
                if (redisTemplate.opsForHash().hasKey(key, hashLoveKey)) {
                    movementsVO.setHasLoved(1);
                }
                movementsVOs.add(movementsVO);
            }
        }
        pageResult.setItems(movementsVOs);
        return pageResult;
    }

    /**
     * 圈子-查询单条动态
     * @param movementId
     * @return
     */
    public MovementsVO findSingleMovement(String movementId) {
        Movement movement = movementApi.findById(movementId);
        if (ObjectUtil.isEmpty(movement)) {
            throw new BusinessException(ErrorResult.error());
        }
        UserInfo userInfo = userInfoApi.selectById(movement.getUserId());
        //发送日志
        mqMessageService.sendLogMessage(
                UserHolder.getUserId(), LogType.MOVEMENT_BROWSE, LogKey.MOVEMENT, movementId);
        return MovementsVO.init(userInfo, movement);
    }

    /**
     * 圈子-动态互动-(取消)点赞、(取消)喜欢
     * @param movementId
     * @param choose
     * @param commentType
     * @param commentSubject
     * @return
     */
    public Integer disposeComment(String movementId,
                                  Boolean choose,
                                  CommentType commentType,
                                  CommentSubject commentSubject) {
        //调用CommentApi查询用户是否已点赞/喜欢(hasComment)
        Long userId = UserHolder.getUserId();
        Boolean hasComment = commentApi.hasComment(userId, movementId, commentType);
        //根据请求的操作方向(choose)和查询到的操作状态(hasComment)判断是否重复操作
        //如果操作方向和操作状态一致(同true或同false)，抛出异常
        if (hasComment && choose) {
            if (commentType.equals(CommentType.LIKE)) {
                throw new BusinessException(ErrorResult.likeError());
            } else {
                throw new BusinessException(ErrorResult.loveError());
            }
        }
        if (!hasComment && !choose) {
            if (commentType.equals(CommentType.LIKE)) {
                throw new BusinessException(ErrorResult.disLikeError());
            } else {
                throw new BusinessException(ErrorResult.disloveError());
            }
        }
        //操作方向不一致，调用CommentApi操作数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setUserId(userId);
        comment.setCommentType(commentType.getType());
        //拼接redis，更新用户点赞/喜欢状态
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String keyValue = Constants.MOVEMENT_LIKE_HASHKEY + userId;
        if (commentType.equals(CommentType.LOVE)) {
            keyValue = Constants.MOVEMENT_LOVE_HASHKEY + userId;
        }
        Integer count = 0;
        if (choose) {
            comment.setCreated(System.currentTimeMillis());
            redisTemplate.opsForHash().put(key, keyValue, "1");
            count = commentApi.save(comment, commentSubject);
        } else {
            redisTemplate.opsForHash().delete(key, keyValue);
            count = commentApi.delete(comment, commentSubject);
        }
        //发送日志
        switch (commentSubject) {
            case MOVEMENT: {
                if (commentType.equals(CommentType.LIKE)) {
                    if (choose) {
                        mqMessageService.sendLogMessage(
                                UserHolder.getUserId(),
                                LogType.MOVEMENT_LIKE,
                                LogKey.MOVEMENT, movementId);
                    } else {
                        mqMessageService.sendLogMessage(
                                UserHolder.getUserId(),
                                LogType.MOVEMENT_DISLIKE,
                                LogKey.MOVEMENT, movementId);
                    }
                } else if (commentType.equals(CommentType.LOVE)) {
                    if (choose) {
                        mqMessageService.sendLogMessage(
                                UserHolder.getUserId(),
                                LogType.MOVEMENT_LOVE,
                                LogKey.MOVEMENT, movementId);
                    } else {
                        mqMessageService.sendLogMessage(
                                UserHolder.getUserId(),
                                LogType.MOVEMENT_UNLOVE,
                                LogKey.MOVEMENT, movementId);
                    }
                }
                break;
            }
            case VIDEO: {
                if (commentType.equals(CommentType.LIKE)) {
                    if (choose) {
                        mqMessageService.sendLogMessage(
                                UserHolder.getUserId(),
                                LogType.VIDEO_LIKE,
                                LogKey.VIDEO, movementId);
                    } else {
                        mqMessageService.sendLogMessage(
                                UserHolder.getUserId(),
                                LogType.VIDEO_DISLIKE,
                                LogKey.VIDEO, movementId);
                    }
                }
                break;
            }
            default:
                break;
        }

        log.info("count:{}", count);
        return count;
    }

    /**
     * 交友-谁看过我
     * @return
     */
    public List<VisitorsVO> visitors() {
        Long userId = UserHolder.getUserId();
        //查询访问时间
        String key = Constants.VISITORS_USER;
        String hashKey = userId.toString();
        String value = (String) redisTemplate.opsForHash().get(key, hashKey);
        Long date = StringUtils.isEmpty(value) ? null : Long.valueOf(value);
        //查询数据列表
        List<Visitors> visitors = visitorsApi.getList(userId, date);
        if (CollUtil.isEmpty(visitors)) {
            return new ArrayList<>();
        }
        //提取访客id
        List<Long> userIds = CollUtil.getFieldValues(visitors, "visitorUserId", Long.class);
        //查看用户详情
        Map<Long, UserInfo> map = userInfoApi.selectByIdsAndCondition(userIds, null);
        //构造vo对象并返回
        List<VisitorsVO> visitorsVOs = new ArrayList<>();
        for (Visitors visitor : visitors) {
            UserInfo userInfo = map.get(visitor.getVisitorUserId());
            if (ObjectUtil.isNotEmpty(userInfo)) {
                visitorsVOs.add(VisitorsVO.init(userInfo, visitor));
            }
        }
        return visitorsVOs;
    }
}
